home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 26
/
CU Amiga Magazine's Super CD-ROM 26 (1998)(EMAP Images)(GB)[!][issue 1998-09].iso
/
CUCD
/
PowerPC
/
uae-0.8.4
/
amiga
/
source
/
undms.c
< prev
Wrap
C/C++ Source or Header
|
1998-06-06
|
36KB
|
1,087 lines
/* $VER: undms 1.0 (6.2.98) */
/* Created: 30.1.98 */
/* DMS Extract in (supposedly) portable C. */
/* Compile with: */
/* gcc undms.c -oundms -O2 */
/* I coded this to make sure it would work with unsigned bytes to try */
/* and make it as portable as possible. It should be transparent to */
/* byte order and alignment. Checking of EOF and number of tracks is */
/* quite primitive and could no doubt be improved. The decrunch */
/* functions all check for out of bounds data so no overwriting of */
/* buffers should be possible, even for severly corrupt data. */
/* Decryption is NOT supported at this time. (btw. it is very weak and */
/* there is even code in some DMS programs which allow a brute force */
/* scanning of passwords) */
/* --------------------------------------------------------------------- */
#include <stdio.h>
/* --------------------------------------------------------------------- */
int DEBUG;
#define BUFFERSIZE 16000
unsigned char pack_buffer[BUFFERSIZE];
unsigned char unpack_buffer[BUFFERSIZE];
unsigned char info_header[4];
unsigned char archive_header[52];
unsigned char track_header[20];
unsigned char quick_buffer[256];
unsigned char medium_buffer[16384];
unsigned char deep_buffer[16384];
unsigned short deep_weights[628];
unsigned short deep_symbols[628];
unsigned short deep_hash[942];
unsigned char heavy_buffer[8192];
unsigned short heavy_literal_table[5120];
unsigned short heavy_offset_table[320];
unsigned char heavy_literal_len[512];
unsigned char heavy_offset_len[32];
unsigned int quick_local;
unsigned int medium_local;
unsigned int deep_local;
unsigned int heavy_local;
unsigned int heavy_last_offset;
unsigned int pack_size;
unsigned int rle_size;
unsigned int unpack_size;
unsigned int high_track;
unsigned int no_clear_flag;
/* --------------------------------------------------------------------- */
static const unsigned short CRCTable[256]=
{
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
};
/* --------------------------------------------------------------------- */
static const unsigned char table_one[256]=
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,
10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,
12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,
16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,
20,20,20,20,21,21,21,21,22,22,22,22,23,23,23,23,
24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,
32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,
40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
};
static const unsigned char table_two[256]=
{
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
};
/* --------------------------------------------------------------------- */
unsigned int mycrc(unsigned char *memory, unsigned int length)
{
register unsigned int temp = 0;
while(length--)
temp = CRCTable[(temp ^ *memory++) & 255] ^ ((temp >> 8) & 255);
return (temp & 65535);
}
/* --------------------------------------------------------------------- */
unsigned int mysimplecrc(unsigned char *memory, unsigned int length)
{
register unsigned int temp = 0;
while(length--) temp = temp + (*memory++ & 255);
return (temp & 65535);
}
/* --------------------------------------------------------------------- */
int crunch_store(unsigned char *source, unsigned char *source_end,
unsigned char *destination, unsigned char *destination_end)
{
while((destination < destination_end) && (source < source_end))
*destination++ = *source++;
if(DEBUG)printf(" ...store %s",((source != source_end) || (destination != destination_end)) ? "bad" : "good");
return((source != source_end) || (destination != destination_end));
}
/* --------------------------------------------------------------------- */
int crunch_rle(unsigned char *source, unsigned char *source_end,
unsigned char *destination, unsigned char *destination_end)
{
register unsigned char temp;
register int count;
while((destination < destination_end) && (source < source_end))
{
if((temp = *source++) != 144) /* crunch_dle */
{
*destination++ = temp;
}
else if((count = *source++) == 0)
{
*destination++ = temp;
}
else
{
temp = *source++;
if(count == 255)
{
count = *source++ << 8;
count += *source++;
}
while((destination < destination_end) && (count--))
*destination++ = temp;
}
} /* while */
if(DEBUG)printf(" ...runlength %s",((source != source_end) || (destination != destination_end)) ? "bad" : "good");
return((source != source_end) || (destination != destination_end));
}
/* --------------------------------------------------------------------- */
int crunch_quick(unsigned char *source, unsigned char *source_end,
unsigned char *destination, unsigned char *destination_end)
{
register unsigned int control = 0;
register int shift = 0;
int count, offset;
quick_local += 5; /* i have no idea why it adds 5 */
if(!no_clear_flag)
for(quick_local = count = 0; count < 256; count++)
quick_buffer[count] = 0;
while((destination < destination_end) && (source < source_end))
{
control <<= 9; /* all codes are at least 9 bits long */
if((shift += 9) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
if(control & 33554432)
{
*destination++ = quick_buffer[quick_local++ & 255] = control >> 16;
}
else
{
control <<= 2; /* 2 extra bits for length */
if((shift += 2) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
count = ((control >> 24) & 3) + 2;
offset = quick_local - ((control >> 16) & 255) - 1;
while((destination < destination_end) && (count--))
*destination++ = quick_buffer[quick_local++ & 255] =
quick_buffer[offset++ & 255];
}
} /* while */
if(DEBUG)printf(" ...quick %s",((source > source_end) || (destination != destination_end)) ? "bad" : "good", source, source_end, destination, destination_end);
return((source > source_end) || (destination != destination_end));
}
/* --------------------------------------------------------------------- */
int crunch_medium(unsigned char *source, unsigned char *source_end,
unsigned char *destination, unsigned char *destination_end)
{
register unsigned int control = 0;
register int shift = 0;
int count, offset, temp;
medium_local += 66; /* i have no idea why it adds 66 */
if(!no_clear_flag)
for(medium_local = count = 0; count < 16384; count++)
medium_buffer[count] = 0;
while((destination < destination_end) && (source < source_end))
{
control <<= 9; /* all codes are 9 bits long */
if((shift += 9) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
if((temp = (control >> 16) & 511) >= 256)
{
*destination++ = medium_buffer[medium_local++ & 16383] = temp;
}
else
{
count = table_one[temp] + 3;
temp = table_two[temp];
control <<= temp;
if((shift += temp) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
temp = (control >> 16) & 255;
offset = table_one[temp] << 8;
temp = table_two[temp];
control <<= temp;
if((shift += temp) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
offset += (control >> 16) & 255;
offset = medium_local - offset - 1;
while((destination < destination_end) && (count--))
*destination++ = medium_buffer[medium_local++ & 16383] =
medium_buffer[offset++ & 16383];
}
} /* while */
if(DEBUG)printf(" ...medium %s",((source > source_end) || (destination != destination_end)) ? "bad" : "good");
return((source > source_end) || (destination != destination_end));
}
/* --------------------------------------------------------------------- */
void deep_clear()
{
unsigned short count, temp;
temp = 627;
for(count = 0; count < 314; count++)
{
deep_weights[count] = 1;
deep_symbols[count] = temp;
deep_hash[temp] = count;
temp++;
}
temp = 0;
for(count = 314; count < 627; count++)
{
deep_weights[count] = deep_weights[temp] + deep_weights[temp + 1];
deep_symbols[count] = temp;
deep_hash[temp] = deep_hash[temp + 1] = count;
temp += 2;
}
deep_weights[count] = 65535;
deep_hash[temp] = 0;
if(DEBUG)printf(" ...clear");
}
/* --------------------------------------------------------------------- */
void deep_scale()
{
int symbol, swap, temp, weight;
temp = 0;
for(symbol = 0; symbol < 627; symbol++)
{
if(deep_symbols[symbol] >= 627)
{
deep_weights[temp] = (deep_weights[symbol] + 1) >> 1;
deep_symbols[temp] = deep_symbols[symbol];
temp++;
}
}
temp = 0;
for(symbol = 314; symbol < 627; symbol++)
{
weight = deep_weights[temp] + deep_weights[temp + 1];
for(swap = symbol; deep_weights[swap - 1] > weight; swap--)
{
deep_weights[swap] = deep_weights[swap - 1];
deep_symbols[swap] = deep_symbols[swap - 1];
}
deep_weights[swap] = weight;
deep_symbols[swap] = temp;
temp += 2;
}
for(symbol = 0; symbol < 627; symbol++)
{
temp = deep_symbols[symbol];
deep_hash[temp] = symbol; if(temp < 627) deep_hash[temp + 1] = symbol;
}
if(DEBUG)printf(" ...scale");
}
/* --------------------------------------------------------------------- */
int crunch_deep(unsigned char *source, unsigned char *source_end,
unsigned char *destination, unsigned char *destination_end)
{
register unsigned int control = 0;
register int shift = 0;
int count, offset, temp, symbol, swap, temp1, temp2;
deep_local += 60; /* i have no idea why it adds 60 */
if(!no_clear_flag)
{
deep_clear();
for(deep_local = count = 0; count < 16384; count++)
deep_buffer[count] = 0;
}
while((destination < destination_end) && (source < source_end))
{
count = deep_symbols[626]; /* start from the root of the trie */
do
{
if(!shift++)
{
control += *source++ << 8;
control += *source++;
shift = -15;
}
control <<= 1;
count += (control >> 16) & 1;
} while((count = deep_symbols[count]) < 627);
if(deep_weights[626] == 32768) /* scale the trie if the weight gets too large */
deep_scale();
symbol = deep_hash[count];
do
{
deep_weights[symbol]++; /* increase the weight of this node */
if(deep_weights[symbol + 1] < deep_weights[symbol])
{
temp1 = deep_weights[(swap = symbol)];
do
{
swap++;
} while(deep_weights[swap + 1] < temp1);
deep_weights[symbol] = deep_weights[swap];
deep_weights[swap] = temp1;
temp1 = deep_symbols[symbol];
temp2 = deep_symbols[swap];
deep_symbols[swap] = temp1;
deep_symbols[symbol] = temp2;
deep_hash[temp1] = swap; if(temp1 < 627) deep_hash[temp1 + 1] = swap;
deep_hash[temp2] = symbol; if(temp2 < 627) deep_hash[temp2 + 1] = symbol;
symbol = swap;
}
} while(symbol = deep_hash[symbol]); /* repeat until we reach root */
if((count -= 627) < 256)
{
*destination++ = deep_buffer[deep_local++ & 16383] = count;
}
else
{
count -= 253; /* length is always at least 3 characters */
control <<= 8;
if((shift += 8) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
temp = (control >> 16) & 255;
offset = table_one[temp] << 8;
temp = table_two[temp];
control <<= temp;
if((shift += temp) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
offset += (control >> 16) & 255;
offset = deep_local - offset - 1;
while((destination < destination_end) && (count--))
*destination++ = deep_buffer[deep_local++ & 16383] =
deep_buffer[offset++ & 16383];
}
} /* while */
if(DEBUG)printf(" ...deep %s",((source > source_end) || (destination != destination_end)) ? "bad" : "good");
return((source > source_end) || (destination != destination_end));
}
/* --------------------------------------------------------------------- */
int make_decode_table(int number_symbols, int table_size,
unsigned char *length, unsigned short *table)
{
register unsigned char bit_num = 0;
register int symbol;
unsigned int table_mask, bit_mask, pos, fill, next_symbol, leaf;
int abort = 0;
pos = 0;
fill = 0;
bit_mask = table_mask = 1 << table_size;
while((!abort) && (bit_num <= table_size))
{
for(symbol = 0; symbol < number_symbols; symbol++)
{
if(length[symbol] == bit_num)
{
if((pos += bit_mask) > table_mask)
{
abort = 1;
break; /* we will overrun the table! abort! */
}
while(fill < pos)
table[fill++] = symbol;
}
}
bit_mask >>= 1;
bit_num++;
}
if((!abort) && (pos != table_mask))
{
for(; fill < table_mask; fill++)
table[fill] = 0; /* clear the rest of the table */
next_symbol = table_mask >> 1;
pos <<= 16;
table_mask <<= 16;
bit_mask = 32768;
while((!abort) && (bit_num <= 18))
{
for(symbol = 0; symbol < number_symbols; symbol++)
{
if(length[symbol] == bit_num)
{
leaf = pos >> 16;
for(fill = 0; fill < bit_num - table_size; fill++)
{
if(table[leaf] == 0)
{
table[(next_symbol << 1)] = 0;
table[(next_symbol << 1) + 1] = 0;
table[leaf] = next_symbol++;
}
leaf = table[leaf] << 1;
leaf += (pos >> (15 - fill)) & 1;
}
table[leaf] = symbol;
if((pos += bit_mask) > table_mask)
{
abort = 1;
break; /* we will overrun the table! abort! */
}
}
}
bit_mask >>= 1;
bit_num++;
}
}
if(DEBUG)printf(" ...table %s",((pos != table_mask) || abort) ? "bad" : "good");
return((pos != table_mask) || abort);
}
/* --------------------------------------------------------------------- */
int crunch_heavy(unsigned char *source, unsigned char *source_end,
unsigned char *destination, unsigned char *destination_end,
int flag, int special)
{
register unsigned int control = 0;
register int shift = 0;
int count, offset, temp;
if(!no_clear_flag) heavy_local = 0;
if(flag)
{
for(count = 0; count < 512; count++)
heavy_literal_len[count] = 255;
for(count = 0; count < 32; count++)
heavy_offset_len[count] = 255;
flag = 0;
/* read the literal table */
{
control <<= 9; /* get number of literals */
if((shift += 9) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
if(offset = (control >> 16) & 511)
for(count = 0; count < offset; count++)
{
control <<= 5; /* get the length of this literal */
if((shift += 5) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
temp = (control >> 16) & 31;
heavy_literal_len[count] = (temp ? temp : 255);
}
else
{
control <<= 9; /* get the defined literal */
if((shift += 9) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
heavy_literal_len[(control >> 16) & 511] = 0;
}
flag |= make_decode_table(512, 12, heavy_literal_len, heavy_literal_table);
}
/* read the offset table */
{
control <<= 5; /* get number of offsets */
if((shift += 5) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
if(offset = (control >> 16) & 31)
for(count = 0; count < offset; count++)
{
control <<= 4; /* get the length of this offset */
if((shift += 4) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
temp = (control >> 16) & 15;
heavy_offset_len[count] = (temp ? temp : 255);
}
else
{
control <<= 5; /* get the defined offset */
if((shift += 5) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
heavy_offset_len[(control >> 16) & 31] = 0;
}
temp = heavy_offset_len[special];
heavy_offset_len[special] = heavy_offset_len[31];
heavy_offset_len[31] = temp;
flag |= make_decode_table(32, 8, heavy_offset_len, heavy_offset_table);
}
} /* if(flag) */
if(!flag)
{
/* prefetch 12 bits for fast huffman decoding */
control <<= 12;
if((shift += 12) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
while((destination < destination_end) && (source < source_end))
{
/* get a literal */
if((count = heavy_literal_table[(control >> 16) & 4095]) >= 512)
{
do /* literal is longer than 12 bits */
{
if(!shift++)
{
control += *source++ << 8;
control += *source++;
shift = -15;
}
control <<= 1;
count = heavy_literal_table[((control >> 16) & 1) + (count << 1)];
} while(count >= 512);
temp = 12; /* skip the original 12 bits */
}
else
{
temp = heavy_literal_len[count];
}
control <<= temp;
if((shift += temp) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
/* less than 256 = literal, otherwise = length of string */
if(count < 256)
{
*destination++ = heavy_buffer[heavy_local++ & 8191] = count;
}
else /* must have been a string */
{
count -= 253; /* length is always at least 3 characters */
if((offset = heavy_offset_table[(control >> 20) & 255]) >= 32)
{
do /* offset is longer than 8 bits */
{
if(!shift++)
{
control += *source++ << 8;
control += *source++;
shift = -15;
}
control <<= 1;
offset = heavy_offset_table[((control >> 20) & 1) + (offset << 1)];
} while(offset >= 32);
temp = 8; /* skip the original 8 bits */
}
else
{
temp = heavy_offset_len[offset];
}
control <<= temp;
if((shift += temp) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
if(offset == 31)
{
offset = heavy_last_offset;
}
else
{
if(offset)
{
temp = offset - 1;
offset = ((control & 268369920) | 268435456) >> (28 - temp);
control <<= temp;
if((shift += temp) > 0)
{
control += *source++ << (8 + shift);
control += *source++ << shift;
shift -= 16;
}
}
heavy_last_offset = offset;
}
offset = heavy_local - offset - 1;
while((destination < destination_end) && (count--))
*destination++ = heavy_buffer[heavy_local++ & 8191] =
heavy_buffer[offset++ & 8191];
} /* if(string) */
}
} /* if(!flag) */
if(DEBUG)printf(" ...heavy %s",((source > source_end) || (destination != destination_end) || flag) ? "bad" : "good");
return((source > source_end) || (destination != destination_end) || flag);
}
/* --------------------------------------------------------------------- */
int main(int argc, char ** argv)
{
int in_file, out_file;
int result = 1; /* assume an error */
int abort = 0;
unsigned int current_track;
unsigned char pack_mode;
unsigned char *buffer;
no_clear_flag = 0;
if (argc >= 3)
{
DEBUG = (argc >= 4);
if((in_file = open(argv[1],0)) >= 0)
{
if(read(in_file, info_header, 4) == 4)
{
if((info_header[0] == 68) && (info_header[1] == 77) && /* DMS! */
(info_header[2] == 83) && (info_header[3] == 33))
{
if(read(in_file, archive_header, 52) == 52)
{
if(mycrc(archive_header, 50) ==
(archive_header[50] << 8) + archive_header[51]) /* header_sum */
{
if(((archive_header[44] << 8) + archive_header[45]) <= 153) /* extract_ver */
{
if((out_file = creat(argv[2],384)) >= 0)
{
high_track = ((archive_header[14]) << 8) + archive_header[15]; /* hightrack */
high_track = (high_track <= 80) ? high_track : 80;
while(!abort)
{
abort = 1; /* assume an error */
buffer = 0; /* assume an error */
if(read(in_file, track_header, 20) == 20)
{
if((track_header[0] == 84) && track_header[1] == 82) /* TR */
{
if(mycrc(track_header, 18) == ((track_header[18] << 8) + track_header[19])) /* header_sum */
{
current_track = (track_header[2] << 8) + track_header[3]; /* track */
pack_size = (track_header[6] << 8) + track_header[7]; /* pack_size */
rle_size = (track_header[8] << 8) + track_header[9]; /* rle_size */
unpack_size = (track_header[10] << 8) + track_header[11]; /* unpack_size */
pack_mode = track_header[13]; /* pack_mode */
if((pack_size + 16 < BUFFERSIZE) && (rle_size + 16 < BUFFERSIZE) &&
(unpack_size + 16 < BUFFERSIZE)) /* allow for overrun */
{
if(read(in_file, pack_buffer, pack_size) == pack_size)
{
if(mycrc(pack_buffer, pack_size) ==
((track_header[16] << 8) + track_header[17])) /* data_sum */
{
if(pack_mode < 7)
{
if(DEBUG)printf("track %d pack %d rle %d unpack %d", current_track, pack_size, rle_size, unpack_size);
switch(track_header[13]) /* pack_mode */
{
case 0: /* store */
{
if(!crunch_store(pack_buffer, pack_buffer + pack_size,
unpack_buffer, unpack_buffer + unpack_size))
buffer = unpack_buffer;
break;
}
case 1: /* rle */
{
if(!crunch_rle(pack_buffer, pack_buffer + pack_size,
unpack_buffer, unpack_buffer + unpack_size))
buffer = unpack_buffer;
break;
}
case 2: /* quick */
{
if(!crunch_quick(pack_buffer, pack_buffer + pack_size + 16,
unpack_buffer, unpack_buffer + rle_size))
if(!crunch_rle(unpack_buffer, unpack_buffer + rle_size,
pack_buffer, pack_buffer + unpack_size))
buffer = pack_buffer;
break;
}
case 3: /* medium */
{
if(!crunch_medium(pack_buffer, pack_buffer + pack_size + 16,
unpack_buffer, unpack_buffer + rle_size))
if(!crunch_rle(unpack_buffer, unpack_buffer + rle_size,
pack_buffer, pack_buffer + unpack_size))
buffer = pack_buffer;
break;
}
case 4: /* deep */
{
if(!crunch_deep(pack_buffer, pack_buffer + pack_size + 16,
unpack_buffer, unpack_buffer + rle_size))
if(!crunch_rle(unpack_buffer, unpack_buffer + rle_size,
pack_buffer, pack_buffer + unpack_size))
buffer = pack_buffer;
break;
}
case 5: /* heavy1 */
{
if(!crunch_heavy(pack_buffer, pack_buffer + pack_size + 16,
unpack_buffer, unpack_buffer + rle_size,
track_header[12] & 2, 13))
{
if(track_header[12] & 4) /* pack_flag */
{
if(!crunch_rle(unpack_buffer, unpack_buffer + rle_size,
pack_buffer, pack_buffer + unpack_size))
buffer = pack_buffer;
}
else
buffer = unpack_buffer;
}
break;
}
case 6: /* heavy2 */
{
if(!crunch_heavy(pack_buffer, pack_buffer + pack_size + 16,
unpack_buffer, unpack_buffer + rle_size,
track_header[12] & 2, 14))
{
if(track_header[12] & 4) /* pack_flag */
{
if(!crunch_rle(unpack_buffer, unpack_buffer + rle_size,
pack_buffer, pack_buffer + unpack_size))
buffer = pack_buffer;
}
else
buffer = unpack_buffer;
}
break;
}
} /* switch */
if(DEBUG)printf("\n");
if(buffer)
{
if(mysimplecrc(buffer, unpack_size) == ((track_header[14] << 8) + track_header[15])) /* unpack_sum */
{
if((current_track < 1000) && (unpack_size >= 8192)) /* try and skip illegal tracks */
{
if(write(out_file, buffer, unpack_size) == unpack_size)
{
if(current_track < high_track)
{
no_clear_flag = track_header[12] & 1; /* pack_flag */
abort = 0; /* continue */
}
else
result = 0; /* successful completion */
}
else
perror("Write()");
}
else
abort = 0; /* skip this chunk */
}
else
puts("CRC: Unpack_Data");
}
else
puts("Extract failed");
}
else
puts("Unknown Pack_Mode");
}
else
puts("CRC: Track_Buffer");
}
else
perror("Read(Track_Data)");
}
else
puts("Unpack buffers are too small");
}
else
puts("CRC: Track_Header");
}
else
puts("Unknown Track_Header");
}
else
perror("Read(Track_Header)");
} /* while */
close(out_file);
}
else
perror("Open(Destination)");
}
else
puts("Need newer extractor");
}
else
puts("CRC: Archive_Header");
}
else
perror("Read(Archive_Header)");
}
else
puts("Unknown Info_Header");
}
else
perror("Read(Info_Header)");
close(in_file);
}
else
perror("Open(Source)");
}
else
{
puts("Usage: undms source destination");
result = 0;
}
return(result);
}
/* --------------------------------------------------------------------- */
/* Absolutely for the reader ONLY. This is basically hardcoded into */
/* the program. You don't like it? TS */
/* struct Info_Header
{
LONG ID; 0 : 'DMS!'
} */ /* SIZE = 4 */
/* general purpose flags */
#define GENERAL_NOZERO 1<<0
#define GENERAL_ENCRYPT 1<<1
#define GENERAL_OPTIMIZED 1<<2
#define GENERAL_BANNER 1<<3
/* serial number of creator */
#define SERIAL_NUMBER 0 /* generic */
/* cpu type of creator */
#define CPU_MC68000 1
#define CPU_MC68010 2
#define CPU_MC68020 3
#define CPU_MC68030 4
#define CPU_MC68040 5
#define CPU_MC68050 6
#define CPU_IAPX86 7
#define CPU_IAPX88 8
#define CPU_IAPX188 9
#define CPU_IAPX186 10
#define CPU_IAPX286 11
#define CPU_IAPX386SX 12
#define CPU_IAPX386 13
#define CPU_IAPX486 14
#define CPU_IAPX586 15
/* coprocessor of creator */
#define COPRO_MC68881 1
#define COPRO_MC68882 2
#define COPRO_IAPX87 3
#define COPRO_IAPX287 4
#define COPRO_IAPX387SX 5
#define COPRO_IAPX387 6
/* machine type of creator */
#define MACHINE_AMIGA 1
#define MACHINE_PC 2
#define MACHINE_ATARI 3
#define MACHINE_MAC 4
/* disk types */
#define DISKTYPE_AMIGA1_OFS 1
#define DISKTYPE_AMIGA1_FFS 2
#define DISKTYPE_MSDOS 3
#define DISKTYPE_AMAX 4
#define DISKTYPE_MAC 5
/* struct Archive_Header
{
LONG extra; 0 : for future expansion
LONG general; 4 : general purpose flags
LONG timestamp; 8 : creation date of archive (seconds since 00:00:00 01-Jan-78)
SHORT lowtrack; 12 : first track (0-85)
SHORT hightrack; 14 : last track (0-85)
LONG pack_size; 16 : total size of data after compression
LONG unpack_size; 20 : total size of data before compression
LONG serialno; 24 : serial number of creator
SHORT cpu; 28 : CPU type of creator
SHORT copro; 30 : CPU coprocessor of creator
SHORT machine; 32 : machine of creator
SHORT mextra; 34 : extra ID information (machine specific)
SHORT speed; 36 : CPU speed (approx)
LONG timecreate; 38 : time to create archive
SHORT create_ver; 42 : version of creator
SHORT extract_ver; 44 : version needed to extract
SHORT disktype; 46 : disk type of archive
SHORT crunchmode; 48 : compression mode (generally) used
SHORT header_sum; 50 : header CRC
} */ /* SIZE = 52 */
/* crunch mode */
#define CRUNCH_NOCOMP 0 /* Compression modes */
#define CRUNCH_RLE 1
#define CRUNCH_QUICK 2
#define CRUNCH_MEDIUM 3
#define CRUNCH_DEEP 4
#define CRUNCH_TESTPACK 5
#define CRUNCH_DLE 0x90
/* struct Track_Header
{
SHORT ID; 0 : 'TR'
SHORT track; 2 : track number -1=text
SHORT flags; 4 : general flags
SHORT pack_size; 6 : packed length
SHORT rle_size; 8 : rle-packed size
SHORT unpack_size; 10 : unpacked size
BYTE pack_flag; 12 : general purpose compression flag
BYTE pack_mode; 13 : compression mode
SHORT unpack_sum; 14 : unpacked CRC
SHORT data_sum; 16 : packed CRC
SHORT header_sum; 18 : header CRC
} */ /* SIZE = 20 */
/* --------------------------------------------------------------------- */